package com.yojcodesendbox.util;

import cn.hutool.core.date.StopWatch;
import cn.hutool.core.io.FileUtil;
import com.yojcodesendbox.constant.FileConstant;
import com.yojcodesendbox.model.ExecuteResult;
import com.yojcodesendbox.model.JudgeInfo;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.UUID;


@Component
public class ProcessUtil {

    @Resource
    FileConstant fileConstant;
    /**
     * 执行 cmd 命令, 返回结果
     */
    public ExecuteResult executeCompilCmd(String compilCmd,String inputStr) {

        JudgeInfo judgeInfo = new JudgeInfo();
        try {

            StopWatch stopWatch = new StopWatch();
            stopWatch.start();

            System.out.println("执行：" + compilCmd);
            Process process = Runtime.getRuntime().exec(compilCmd);
            // 超时线程
            Thread backTimeoutThread = new Thread(() -> {
                try {
                    Thread.sleep(fileConstant.timeout);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                } finally {
                    process.destroy();
                }
            });
            // 交互式参数不为空时
            if (inputStr != null && !StringUtils.isEmpty(inputStr)) {
                inputStr = String.join("\n", inputStr.split(" ")) + "\n";
                OutputStream outputStream = process.getOutputStream();
                outputStream.write(inputStr.getBytes(StandardCharsets.UTF_8));
                outputStream.flush();
                outputStream.close();
            }
            int exitValue = process.waitFor();

            stopWatch.stop();
            // 获取执行时间
            long exeTime = stopWatch.getLastTaskTimeMillis();
            judgeInfo.setTime(exeTime);
            //销毁记时进程
            backTimeoutThread.interrupt();
            // 错误
            InputStream inputStream = process.getInputStream();
            String resulteStr = getStringFromInputStream(inputStream);
            // 正确结果
            InputStream errorStream = process.getErrorStream();
            String resultError = getStringFromInputStream(errorStream);

            System.out.println("err:" + resultError + ",resulte:" + resulteStr);

            return new ExecuteResult(exitValue, resulteStr, resultError, judgeInfo);

        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    private static String userCodeFilePath;
    private static String userCodeDir;
    /**
     * 将code写到指定位置下，返回写文件的路径
     */
    public void writeCodeToFile(String code, String fileTail) {
        String userDir = System.getProperty("user.dir");
        String globalCodePathName = userDir + File.separator + fileConstant.globalClassDir + File.separator + fileTail;
        System.out.println("把code copy 到 globalCodePathName" + globalCodePathName);
        // 如果文件夹不存在就创建
        if (!FileUtil.exist(globalCodePathName)) {
            FileUtil.mkdir(globalCodePathName);
        }
        // code文件写到这个目录下
        userCodeDir = globalCodePathName + File.separator + UUID.randomUUID();
        // code写到这个路径下的文件中
        userCodeFilePath = userCodeDir + File.separator + fileConstant.globalClassName + "." + fileTail;
        System.out.println("把code copy 到 userCodeFilePath：" + userCodeFilePath);
        FileUtil.writeString(code, userCodeFilePath, StandardCharsets.UTF_8);
    }

    /**
     * 用户代码复制到这个文件夹下
     */
    public static String getUserCodeDir() {
        // code文件写到这个目录下
        return userCodeDir;
    }
    /**
     * 用户代码复制到这个文件中
     */
    public static String getUserCodeFilePath() {
        return userCodeFilePath;
    }
    /**
     * 删除代码复制到的目录
     */
    public static void delCodeDir() {
        //  删除目录
        File userCodeDirF = new File(userCodeDir);
        if (userCodeDirF.exists()) {
            FileUtil.del(userCodeDirF);
        }
    }

    private static String getStringFromInputStream(InputStream inputStream) throws IOException {

            StringBuilder sbResult = new StringBuilder();
            BufferedReader bufferedReader = new BufferedReader(
                    new InputStreamReader(
                            inputStream
                    ));
            String exeInfoLineStr;
            while ((exeInfoLineStr = bufferedReader.readLine()) != null) {
                System.out.println(exeInfoLineStr);
                sbResult.append(exeInfoLineStr);
            }
            inputStream.close();
            bufferedReader.close();
            return sbResult.toString();

    }
}